﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace GoodTrader.GTUtil
{
    public class Beta
    {
        private const int SWITCH = 3000,MAXIT=1000;
        private const Double EPS = 3.0e-7, FPMIN = 1.0e-30;
        public static Double betai(Double a, Double b, Double x)
        {
	        Double bt;

            if (x < 0.0 || x > 1.0) throw new System.ArgumentException("Bad x in routine betai");
	        if (x == 0.0 || x == 1.0) bt=0.0;
	        else
		        bt=Math.Exp(gammln(a+b)-gammln(a)-gammln(b)+a*Math.Log(x)+b*Math.Log(1.0-x));
	        if (x < (a+1.0)/(a+b+2.0))
		        return bt*betacf(a,b,x)/a;
	        else
		        return 1.0-bt*betacf(b,a,1.0-x)/b;
        }
        private static Double gammln(Double xx)
        {
	        Double x,y,tmp,ser;
	        Double[] cof=new Double[6]{76.18009172947146,-86.50532032941677,
		        24.01409824083091,-1.231739572450155,
		        0.1208650973866179e-2,-0.5395239384953e-5};
	        int j;

	        y=x=xx;
	        tmp=x+5.5;
	        tmp -= (x+0.5)*Math.Log(tmp);
	        ser=1.000000000190015;
	        for (j=0;j<=5;j++) ser += cof[j]/++y;
	        return -tmp+Math.Log(2.5066282746310005*ser/x);
        }

        private static Double betacf(Double a, Double b, Double x)
        {

	        int m,m2;
	        Double aa,c,d,del,h,qab,qam,qap;

	        qab=a+b;
	        qap=a+1.0;
	        qam=a-1.0;
	        c=1.0;
	        d=1.0-qab*x/qap;
	        if (Math.Abs(d) < FPMIN) d=FPMIN;
	        d=1.0/d;
	        h=d;
	        for (m=1;m<=MAXIT;m++) 
            {
		        m2=2*m;
		        aa=m*(b-m)*x/((qam+m2)*(a+m2));
		        d=1.0+aa*d;
                if (Math.Abs(d) < FPMIN) d = FPMIN;
		        c=1.0+aa/c;
                if (Math.Abs(c) < FPMIN) c = FPMIN;
		        d=1.0/d;
		        h *= d*c;
		        aa = -(a+m)*(qab+m)*x/((a+m2)*(qap+m2));
		        d=1.0+aa*d;
                if (Math.Abs(d) < FPMIN) d = FPMIN;
		        c=1.0+aa/c;
                if (Math.Abs(c) < FPMIN) c = FPMIN;
		        d=1.0/d;
		        del=d*c;
		        h *= del;
                if (Math.Abs(del - 1.0) < EPS) break;
	        }
            if (m > MAXIT) throw new System.ArgumentException("a or b too big, or MAXIT too small in betacf");
	        return h;
        }
        public static Double erfcc(Double x)
        {
            Double t, z, ans;

            z = Math.Abs(x);
            t = 1.0 / (1.0 + 0.5 * z);
            ans = t * Math.Exp(-z * z - 1.26551223 + t * (1.00002368 + t * (0.37409196 + t * (0.09678418 +
                t * (-0.18628806 + t * (0.27886807 + t * (-1.13520398 + t * (1.48851587 +
                t * (-0.82215223 + t * 0.17087277)))))))));
            return x >= 0.0 ? ans : 2.0 - ans;
        }
    }
    public static class GTStat
    {
        public static void GetMovingAverage(int frameSize, double[] aSrcData, double[] aOutData)
        {
            /*
            double sum = 0;
            //double[] avgPoints = new double[aSrcData.Length - frameSize + 1];
            for (int counter = 0; counter < aSrcData.Length; counter++)
            {
                int innerLoopCounter = 0;
                int index = counter;
                while (innerLoopCounter < frameSize)
                {
                    sum = sum + aSrcData[index];

                    innerLoopCounter += 1;

                    index += 1;

                }

                avgPoints[counter] = sum / frameSize;

                sum = 0;

            }
            return avgPoints;
             */
            MACalculator mvCal = new MACalculator(frameSize);
            for(int i = 0; i < aSrcData.Length; i++)
            {
                aOutData[i] = mvCal.NextValue(aSrcData[i]);
            }
        }

        public static bool get_correlation(double[] x, double[] y, ref double corr, ref double Rsquare, ref double _alpha, ref double _beta)
        {
            if(x.Length != y.Length) return false;
 
            int n = x.Length;
            if(n == 0) return false;
 
 
            double x_sum = 0;
            double y_sum = 0;
            double x_square_sum = 0;
            double y_square_sum = 0;
            double xy_sum = 0;
 
            for(int i = 0; i < n; i++)
            {
                x_sum += x[i];
                y_sum += y[i];
                x_square_sum += (x[i] * x[i]);
                y_square_sum += (y[i] * y[i]);
                xy_sum += (x[i] * y[i]);
            }

            corr = (n * xy_sum - x_sum * y_sum) / (Math.Sqrt(n * x_square_sum - x_sum * x_sum) * Math.Sqrt(n * y_square_sum - y_sum * y_sum));

            double alpha = (x_sum*y_sum-n*xy_sum)/(x_sum*x_sum-n*x_square_sum);
            double beta = (x_sum*xy_sum - y_sum*x_square_sum)/(x_sum*x_sum-n*x_square_sum);
            _alpha = alpha;
            _beta = beta;
             
            double y_mean = y_sum/n;
            double SStot = 0;
            double SSerr = 0;
            for(int j = 0; j < n; j++)
            {
                SStot += ((y[j] - y_mean)*(y[j] - y_mean));
                SSerr += ((y[j] - alpha*(x[j]) - beta)*(y[j] - alpha*(x[j]) - beta));
            }

            Rsquare = 1 - SSerr / SStot;

            return true;
        }

        public static void GetPearson(double[] x, double[] y,ref Double r,ref Double prob,ref Double prob2,ref Double z)
        {
            //will regularize the unusual case of complete correlation
	        const double TINY=1.0e-20;
	        int j,n=x.Length;
	        Double yt,xt,t,df;
	        Double syy=0.0,sxy=0.0,sxx=0.0,ay=0.0,ax=0.0;
	        for (j=0;j<n;j++) { //finds the mean
		        ax += x[j];
		        ay += y[j];
	        }
	        ax /= n;
	        ay /= n;
	        for (j=0;j<n;j++) {  // compute correlation coefficient
		        xt=x[j]-ax;
		        yt=y[j]-ay;
		        sxx += xt*xt;
		        syy += yt*yt;
		        sxy += xt*yt;
	        }
	        r=sxy/(Math.Sqrt(sxx*syy)+TINY);
	        z=0.5*Math.Log((1.0+r+TINY)/(1.0-r+TINY)); //fisher's z trasnformation
	        df=n-2;
	        t=r*Math.Sqrt(df/((1.0-r+TINY)*(1.0+r+TINY))); //student's t probability
	        prob=Beta.betai(0.5*df,0.5,df/(df+t*t));
	        prob2=Beta.erfcc(Math.Abs(z*Math.Sqrt(n-1.0))/1.4142136); //for a large n
        }
    
        public static ArrayList CalculateMode(params int[] array)
        {
            ArrayList mode = new ArrayList();
            int[] sortArray = new int[array.Length];

            int[,] frequency = new int[array.Length, 2];
            Array.Copy(array, sortArray, array.Length);
            Array.Sort(sortArray);
            int tmp = sortArray[0]; // beginning value
            int index = 0; // index into frequency array
            int i = 0;
            while (i < sortArray.Length)
            {
                frequency[index, 0] = tmp; // copy value

                while (tmp.Equals(sortArray[i]))
                {
                    frequency[index, 1]++;  // count occurances
                    i++;

                    if (i > sortArray.Length - 1) // don't overrun array!
                        break;
                }

                if (i < sortArray.Length)
                {
                    tmp = sortArray[i]; // move to next value
                    index++;
                }
            }
            Array.Clear(sortArray, 0, sortArray.Length); // zero it out

            for (i = 0; i < sortArray.Length; i++)
                sortArray[i] = frequency[i, 1]; // copy the occurance values

            Array.Sort(sortArray); // ascending order

            index = sortArray.Length - 1;

            switch (sortArray[index])
            {
                case 0:
                    mode.Add("none");
                    break;

                case 1:
                    mode.Add("none");
                    break;

                default:
                    for (i = 0; i < frequency.Length / frequency.Rank; i++)
                        if (frequency[i, 1].Equals(sortArray[index]))
                            mode.Add(frequency[i, 0].ToString());
                    // convert mode integer to a string
                    break;
            }
            return mode;
        }

        public static double CalculateMedian(params int[] pNumbers)
        {
            int len = pNumbers.Length;
            if (len == 0)
                throw new System.ArgumentException("No data");

            int size = pNumbers.Length;
            int mid = size / 2;
            double median = (size % 2 != 0) ? (double)pNumbers[mid] :
            ((double)pNumbers[mid] + (double)pNumbers[mid - 1]) / 2;
            return median;
        }
        public static double CalculateMean(params int[] data)
        {
            int len = data.Length;
            if (len == 0)
                throw new System.ArgumentException("No data");

            double sum = 0;
            for (int i = 0; i < data.Length; i++)
                sum += data[i];
            return sum / len;
        }
        public static int CalculateMin(params int[] rest)
        {
            int min = rest[0];
            foreach (int next in rest)
            {
                min = Math.Min(min, next);
            }
            return min;
        }
        public static int CalculateMax(params int[] rest)
        {
            int max = rest[0];
            foreach (int next in rest)
            {
                max = Math.Max(max, next);
            }
            return max;
        }

        public static void GetCovar(double[,] matrix)
        {
            int x = matrix.GetLength(0); 
            int y = matrix.GetLength(1); 
            //Subtract Means
            Double[,] SubMeansResult = new double[x, y];
            for (int i = 0; i < y; i++)
            {
                var tmp = 0d;
                    for (int j = 0; j < x; j++)
                    {
                        tmp += matrix[j,i];

                    }
                    var mean = tmp / x;
                    for (int j = 0; j < x; j++)
                    {
                        SubMeansResult[j,i] = matrix[j,i] - mean;
                    }
             }
            //Traspose
            Double[,] Transresult = new double[y, x];
            for (int i = 0; i < x; i++)
                for (int j = 0; j < y; j++)
                    Transresult[j, i] = matrix[i, j];

            //Multiply
            y = SubMeansResult.GetLength(0); //X
            x = Transresult.GetLength(1); //Y
            Double[,] MultiplyResult = new double[x, y];
            for (int i = 0; i < x; i++)
            {
                for (int j = 0; j < y; j++)
                {
                    double temp = MultiplyResult[i, j];
                    for (int k = 0; k < x; k++)
                    {
                        temp += Transresult[i, k] * SubMeansResult[i, k];
                    }
                    MultiplyResult[i, j] = temp;
                }

                //normalizing the resulting matrix
                for (int id =0; id<x; id++)
                {
                    for (int j = 0; j < y; j++)
                    {
                        double tmp = MultiplyResult[id,j];
                        tmp /= y - 1;
                        MultiplyResult[id,j] = tmp;
                    }
                }
            }
        }
    }
}
